{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = \"all\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.手动遍历迭代器\n",
    "\n",
    "动的遍历可迭代对象，使用 `next()` 函数并在代码中捕获 `StopIteration` 异常。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def manual_iter():\n",
    "    with open('/etc/passwd') as f:\n",
    "        try:\n",
    "            while True:\n",
    "                line = next(f)\n",
    "                print(line, end='')\n",
    "        except StopIteration:\n",
    "            pass\n",
    "\n",
    "# manual_iter()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "ename": "StopIteration",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mStopIteration\u001b[0m                             Traceback (most recent call last)",
      "\u001b[0;32m/tmp/ipykernel_2390508/1359169986.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m     10\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mit\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     11\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mit\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mit\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mStopIteration\u001b[0m: "
     ]
    }
   ],
   "source": [
    "# 迭代期间所发生的基本细节\n",
    "\n",
    "items = [1, 2, 3]\n",
    "\n",
    "# Get the iterator\n",
    "it = iter(items) # Invokes items.__iter__()\n",
    "\n",
    "# Run the iterator\n",
    "next(it) # Invokes it.__next__()\n",
    "next(it)\n",
    "next(it)\n",
    "next(it)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.代理迭代\n",
    "\n",
    "只需要定义一个 __iter__() 方法，将迭代操作代理到容器内部的对象上去。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Node(1)\n",
      "Node(2)\n"
     ]
    }
   ],
   "source": [
    "class Node:\n",
    "    def __init__(self, value):\n",
    "        self._value = value\n",
    "        self._children = []\n",
    "\n",
    "    def __repr__(self):\n",
    "        return 'Node({!r})'.format(self._value)\n",
    "\n",
    "    def add_child(self, node):\n",
    "        self._children.append(node)\n",
    "\n",
    "    def __iter__(self):\n",
    "        # 这里的 iter() 函数的使用简化了代码， \n",
    "        # iter(s) 只是简单的通过调用 s.__iter__() 方法来返回对应的迭代器对象\n",
    "        # 就跟 len(s) 会调用 s.__len__() 原理是一样的\n",
    "        return iter(self._children)\n",
    "\n",
    "root = Node(0)\n",
    "root.add_child(Node(1))\n",
    "root.add_child(Node(2))\n",
    "\n",
    "for ch in root:\n",
    "    print(ch)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.使用生成器创建新的迭代模式\n",
    "\n",
    "一个函数中需要有一个 yield 语句即可将其转换为一个生成器。 跟普通函数不同的是，生成器只能用于迭代操作。 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "4\n",
      "7\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<generator object frange at 0x7f0a9e2026d0>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "7"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "ename": "StopIteration",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mStopIteration\u001b[0m                             Traceback (most recent call last)",
      "\u001b[0;32m/tmp/ipykernel_2264266/1046216385.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m     16\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     17\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 18\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mStopIteration\u001b[0m: "
     ]
    }
   ],
   "source": [
    "def frange(start, stop, step):\n",
    "    x = start\n",
    "    while x < stop:\n",
    "        yield x\n",
    "        x += step\n",
    "\n",
    "# for 循环\n",
    "for n in frange(1, 10, 3):\n",
    "    print(n)\n",
    "\n",
    "# 手动调用\n",
    "f = frange(1, 10, 3)\n",
    "f\n",
    "\n",
    "next(f)\n",
    "next(f)\n",
    "next(f)\n",
    "next(f)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.实现迭代器协议\n",
    "\n",
    "Python的迭代协议要求一个 __iter__() 方法返回一个特殊的迭代器对象， 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。但是它写起来很繁琐，因为迭代器必须在迭代处理过程中维护大量的状态信息。\n",
    "\n",
    "坦白来讲，没人愿意写这么晦涩的代码。将你的迭代器定义为一个生成器后一切迎刃而解。\n",
    "\n",
    "下面比较一下，`生成器版本的迭代器`，与`实现迭代器协议的迭代器`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Node(0)\n",
      "Node(1)\n",
      "Node(3)\n",
      "Node(4)\n",
      "Node(2)\n",
      "Node(5)\n"
     ]
    }
   ],
   "source": [
    "# 生成器版本的迭代器\n",
    "\n",
    "class Node:\n",
    "    def __init__(self, value):\n",
    "        self._value = value\n",
    "        self._children = []\n",
    "\n",
    "    def __repr__(self):\n",
    "        return 'Node({!r})'.format(self._value)\n",
    "\n",
    "    def add_child(self, node):\n",
    "        self._children.append(node)\n",
    "\n",
    "    def __iter__(self):\n",
    "        return iter(self._children)\n",
    "\n",
    "    def depth_first(self):\n",
    "        yield self\n",
    "        for c in self:\n",
    "            yield from c.depth_first()\n",
    "\n",
    "# Example\n",
    "if __name__ == '__main__':\n",
    "    root = Node(0)\n",
    "    child1 = Node(1)\n",
    "    child2 = Node(2)\n",
    "    root.add_child(child1)\n",
    "    root.add_child(child2)\n",
    "    child1.add_child(Node(3))\n",
    "    child1.add_child(Node(4))\n",
    "    child2.add_child(Node(5))\n",
    "\n",
    "    for ch in root.depth_first():\n",
    "        print(ch)\n",
    "    # Outputs Node(0), Node(1), Node(3), Node(4), Node(2), Node(5)\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Node(0)\n",
      "Node(1)\n",
      "Node(3)\n",
      "Node(4)\n",
      "Node(2)\n",
      "Node(5)\n"
     ]
    }
   ],
   "source": [
    "# 实现迭代器协议的迭代器\n",
    "\n",
    "class Node2:\n",
    "    def __init__(self, value):\n",
    "        self._value = value\n",
    "        self._children = []\n",
    "\n",
    "    def __repr__(self):\n",
    "        return 'Node({!r})'.format(self._value)\n",
    "\n",
    "    def add_child(self, node):\n",
    "        self._children.append(node)\n",
    "\n",
    "    def __iter__(self):\n",
    "        return iter(self._children)\n",
    "\n",
    "    def depth_first(self):\n",
    "        return DepthFirstIterator(self)\n",
    "\n",
    "class DepthFirstIterator(object):\n",
    "\n",
    "    def __init__(self, start_node):\n",
    "        self._node = start_node\n",
    "        self._children_iter = None\n",
    "        self._child_iter = None\n",
    "    \n",
    "    def __iter__(self):\n",
    "        return self\n",
    "\n",
    "    def __next__(self):\n",
    "        # Return myself if just started; create an iterator for children\n",
    "        if self._children_iter is None:\n",
    "            self._children_iter = iter(self._node)\n",
    "            return self._node\n",
    "        # If processing a child, return its next item\n",
    "        elif self._child_iter:\n",
    "            try:\n",
    "                nextchild = next(self._child_iter)\n",
    "                return nextchild\n",
    "            except StopIteration:\n",
    "                self._child_iter = None\n",
    "                return next(self)\n",
    "        else:\n",
    "            self._child_iter = next(self._children_iter).depth_first()\n",
    "            return next(self)\n",
    "\n",
    "\n",
    "# Example\n",
    "if __name__ == '__main__':\n",
    "    root = Node2(0)\n",
    "    child1 = Node2(1)\n",
    "    child2 = Node2(2)\n",
    "    root.add_child(child1)\n",
    "    root.add_child(child2)\n",
    "    child1.add_child(Node2(3))\n",
    "    child1.add_child(Node2(4))\n",
    "    child2.add_child(Node2(5))\n",
    "\n",
    "    for ch in root.depth_first():\n",
    "        print(ch)\n",
    "    # Outputs Node(0), Node(1), Node(3), Node(4), Node(2), Node(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.反向迭代\n",
    "\n",
    "你想反方向迭代一个序列，使用内置的 reversed() 函数。\n",
    "\n",
    "反向迭代仅仅当对象的大小可预先确定或者对象实现了 __reversed__() 的特殊方法时才能生效。 如果两者都不符合，那你必须先将对象转换为一个列表才行。\n",
    "\n",
    "定义一个反向迭代器可以使得代码非常的高效， 因为它不再需要将数据填充到一个列表中然后再去反向迭代这个列表。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4\n",
      "3\n",
      "2\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "a = [1, 2, 3, 4]\n",
    "for i in reversed(a):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5\n",
      "4\n",
      "3\n",
      "2\n",
      "1\n",
      "--------------------\n",
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "class Countdown:\n",
    "    def __init__(self, start):\n",
    "        self.start = start\n",
    "    \n",
    "    # Forward iterator\n",
    "    def __iter__(self):\n",
    "        n = self.start\n",
    "        while n > 0:\n",
    "            yield n\n",
    "            n -= 1\n",
    "\n",
    "    # Reverse iterator\n",
    "    def __reversed__(self):\n",
    "        n = 1\n",
    "        while n <= self.start:\n",
    "            yield n\n",
    "            n += 1\n",
    "\n",
    "for rr in Countdown(5):\n",
    "    print(rr)\n",
    "\n",
    "print('-'*20)\n",
    "\n",
    "for rr in reversed(Countdown(5)):\n",
    "    print(rr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6.带有外部状态的生成器函数\n",
    "\n",
    "如果你想让你的生成器暴露外部状态给用户， 你可以简单的将它实现为一个类，然后把生成器函数放到 __iter__() 方法中过去。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "30, sshd:x:111:65534::/run/sshd:/usr/sbin/nologin\n",
      "\n",
      "31, systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin\n",
      "\n",
      "32, ubuntu:x:1000:1000:ubuntu:/home/ubuntu:/bin/bash\n",
      "\n"
     ]
    }
   ],
   "source": [
    "from collections import deque\n",
    "\n",
    "class linehistory:\n",
    "    def __init__(self, lines, hislen=3):\n",
    "        self.lines = lines\n",
    "        self.history = deque(maxlen=hislen)\n",
    "    \n",
    "    def __iter__(self):\n",
    "        for lineno, line in enumerate(self.lines, 1):\n",
    "            self.history.append((lineno, line))\n",
    "            yield line\n",
    "        \n",
    "    def clear(self):\n",
    "        self.history.clear()\n",
    "\n",
    "with open('/etc/passwd') as f:\n",
    "    lines = linehistory(f)\n",
    "    for line in lines:\n",
    "        if 'ubuntu' in line:\n",
    "            for lineno, hline in lines.history:\n",
    "                print('{}, {}'.format(lineno, hline))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 7.迭代器切片\n",
    "\n",
    "函数 itertools.islice() 正好适用于在迭代器和生成器上做切片操作。\n",
    "\n",
    "迭代器和生成器不能使用标准的切片操作，因为它们的长度事先我们并不知道(并且也没有实现索引)。\n",
    "\n",
    "函数 islice() 返回一个可以生成指定元素的迭代器，它通过**遍历并丢弃直到切片开始索引位置的所有元素**。 然后才开始一个个的返回元素，并直到切片结束索引位置。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10\n",
      "11\n",
      "12\n",
      "13\n",
      "14\n",
      "15\n",
      "16\n",
      "17\n",
      "18\n",
      "19\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "'generator' object is not subscriptable",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m/tmp/ipykernel_2313184/2426509898.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m     12\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     13\u001b[0m \u001b[0;31m# 标准切片操作\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 14\u001b[0;31m \u001b[0mc\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m20\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: 'generator' object is not subscriptable"
     ]
    }
   ],
   "source": [
    "def count(n):\n",
    "    while True:\n",
    "        yield n\n",
    "        n += 1\n",
    "\n",
    "c = count(0)\n",
    "\n",
    "# 使用itertools.islice做切片操作\n",
    "import itertools\n",
    "for x in itertools.islice(c, 10, 20):\n",
    "    print(x)\n",
    "\n",
    "# 标准切片操作\n",
    "c[10:20]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 8.跳过可迭代对象的开始部分\n",
    "\n",
    "可以使用 itertools 模块中有一些函数。\n",
    "\n",
    "- itertools.dropwhile()\n",
    "- itertools.islice()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "mysql:x:116:120:MySQL Server,,,:/nonexistent:/bin/false\n",
      "\n",
      "dnsmasq:x:117:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin\n",
      "\n"
     ]
    }
   ],
   "source": [
    "import itertools\n",
    "\n",
    "with open('/etc/passwd') as f:\n",
    "    for line in itertools.dropwhile(lambda line: not line.startswith('mysql'), f):\n",
    "        print(line)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "4\n",
      "10\n",
      "15\n",
      "--------------------\n",
      "a\n",
      "b\n",
      "c\n",
      "--------------------\n",
      "a\n",
      "b\n",
      "c\n",
      "1\n",
      "4\n",
      "10\n",
      "15\n"
     ]
    }
   ],
   "source": [
    "import itertools\n",
    "\n",
    "items = ['a', 'b', 'c', 1, 4, 10, 15]\n",
    "for x in itertools.islice(items, 3, None):\n",
    "    print(x)\n",
    "\n",
    "print('-'*20)\n",
    "for x in itertools.islice(items, None, 3):\n",
    "    print(x)\n",
    "\n",
    "print('-'*20)\n",
    "for x in itertools.islice(items, None, None):\n",
    "    print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 9.排列组合的迭代\n",
    "\n",
    "迭代遍历一个集合中元素的所有可能的排列或组合。\n",
    "\n",
    "itertools模块提供了三个函数来解决这类问题。\n",
    "\n",
    "- itertools.permutations()\n",
    "  - 排列\n",
    "  - 元素的顺序不同，也表示不同的排列值\n",
    "- itertools.combinations()\n",
    "  - 组合\n",
    "  - 元素的顺序，但元素相同，表示同一个组合\n",
    "- itertools.combinations_with_replacement()\n",
    "  - 也是排列\n",
    "  - 允许同一个元素被选择多次"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "排列\n",
      "('a', 'b', 'c')\n",
      "('a', 'c', 'b')\n",
      "('b', 'a', 'c')\n",
      "('b', 'c', 'a')\n",
      "('c', 'a', 'b')\n",
      "('c', 'b', 'a')\n",
      "组合\n",
      "('a', 'b')\n",
      "('a', 'c')\n",
      "('b', 'c')\n",
      "元素可重复的排列\n",
      "('a', 'a')\n",
      "('a', 'b')\n",
      "('a', 'c')\n",
      "('b', 'b')\n",
      "('b', 'c')\n",
      "('c', 'c')\n"
     ]
    }
   ],
   "source": [
    "items = ['a', 'b', 'c']\n",
    "\n",
    "import itertools\n",
    "\n",
    "print('排列')\n",
    "for p in itertools.permutations(items):\n",
    "    print(p)\n",
    "\n",
    "print('组合')\n",
    "for p in itertools.combinations(items, 2):\n",
    "    print(p)\n",
    "\n",
    "print('元素可重复的组合')\n",
    "for p in itertools.combinations_with_replacement(items, 2):\n",
    "    print(p)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 10.序列上索引值迭代\n",
    "\n",
    "你想在迭代一个序列的同时跟踪正在被处理的元素索引。\n",
    "\n",
    "内置的 enumerate() 函数可以很好的解决这个问题。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 a\n",
      "1 b\n",
      "2 c\n",
      "--------------------\n",
      "1 a\n",
      "2 b\n",
      "3 c\n"
     ]
    }
   ],
   "source": [
    "my_list = ['a', 'b', 'c']\n",
    "\n",
    "for idx, val in enumerate(my_list):\n",
    "    print(idx, val)\n",
    "\n",
    "print('-'*20)\n",
    "for idx, val in enumerate(my_list, start=1):\n",
    "    print(idx, val)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 1 2\n",
      "1 3 4\n",
      "2 5 6\n",
      "3 7 8\n",
      "--------------------\n"
     ]
    },
    {
     "ename": "ValueError",
     "evalue": "not enough values to unpack (expected 3, got 2)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m/tmp/ipykernel_2313184/1405083330.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      7\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'-'\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0;36m20\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      8\u001b[0m \u001b[0;31m# Error!\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0midx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mval1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mval2\u001b[0m \u001b[0;32min\u001b[0m \u001b[0menumerate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     10\u001b[0m     \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0midx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mval1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mval2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mValueError\u001b[0m: not enough values to unpack (expected 3, got 2)"
     ]
    }
   ],
   "source": [
    "data = [ (1, 2), (3, 4), (5, 6), (7, 8) ]\n",
    "\n",
    "# Correct!\n",
    "for idx, (val1, val2) in enumerate(data):\n",
    "    print(idx, val1, val2)\n",
    "\n",
    "print('-'*20)\n",
    "# Error!\n",
    "for idx, val1, val2 in enumerate(data):\n",
    "    print(idx, val1, val2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 11.同时迭代多个序列\n",
    "\n",
    "你想同时迭代多个序列，每次分别从一个序列中取一个元素。\n",
    "\n",
    "为了同时迭代多个序列，使用 zip() 函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 101\n",
      "5 78\n",
      "4 37\n",
      "2 15\n",
      "10 62\n",
      "7 99\n"
     ]
    }
   ],
   "source": [
    "xpts = [1, 5, 4, 2, 10, 7]\n",
    "ypts = [101, 78, 37, 15, 62, 99]\n",
    "\n",
    "# zip(a, b) 会生成一个可返回元组 (x, y) 的迭代器，其中x来自a，y来自b\n",
    "# 一旦其中某个序列到底结尾，迭代宣告结束。\n",
    "for x,y in zip(xpts, ypts):\n",
    "    print(x, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1, 'w')\n",
      "(2, 'x')\n",
      "(3, 'y')\n",
      "--------------------\n",
      "(1, 'w')\n",
      "(2, 'x')\n",
      "(3, 'y')\n",
      "(None, 'z')\n"
     ]
    }
   ],
   "source": [
    "a = [1, 2, 3]\n",
    "b = ['w', 'x', 'y', 'z']\n",
    "\n",
    "for i in zip(a, b):\n",
    "    print(i)\n",
    "\n",
    "print('-'*20)\n",
    "import itertools\n",
    "for i in itertools.zip_longest(a, b):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 14.不同集合上元素的迭代\n",
    "\n",
    "在多个对象执行相同的操作，但是这些对象在不同的容器中，在不失可读性的情况下避免写重复的循环。\n",
    "\n",
    "itertools.chain() 方法可以用来简化这个任务。 它接受一个可迭代对象列表作为输入，并返回一个迭代器，有效的屏蔽掉在多个容器中迭代细节。 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "x\n",
      "y\n",
      "z\n"
     ]
    }
   ],
   "source": [
    "import itertools\n",
    "\n",
    "a = [1, 2, 3, 4]\n",
    "b = ['x', 'y', 'z']\n",
    "\n",
    "for x in itertools.chain(a, b):\n",
    "    print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 13.创建数据处理管道\n",
    "\n",
    "有点厉害，还是再读一遍原文吧: \n",
    "\n",
    "https://python3-cookbook.readthedocs.io/zh_CN/latest/c04/p13_create_data_processing_pipelines.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 14.展开嵌套的序列\n",
    "\n",
    "可以写一个包含 yield from 语句的递归生成器来轻松解决这个问题。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n",
      "6\n",
      "7\n",
      "8\n",
      "--------------------\n",
      "Dave\n",
      "Paula\n",
      "Thomas\n",
      "Lewis\n"
     ]
    }
   ],
   "source": [
    "from collections.abc import Iterable\n",
    "\n",
    "def flatten(items, ignore_types=(str, bytes)):\n",
    "    for x in items:\n",
    "        if isinstance(x, Iterable) and not isinstance(x, ignore_types):\n",
    "            yield from flatten(x)\n",
    "        else:\n",
    "            yield x\n",
    "        \n",
    "items = [1, 2, [3, 4, [5, 6], 7], 8]\n",
    "for x in flatten(items):\n",
    "    print(x)\n",
    "\n",
    "print('-'*20)\n",
    "items = ['Dave', 'Paula', ['Thomas', 'Lewis']]\n",
    "for x in flatten(items):\n",
    "    print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 15.顺序迭代合并后的排序迭代对象\n",
    "\n",
    "你有一系列排序序列，想将它们合并后得到一个排序序列并在上面迭代遍历。\n",
    "\n",
    "heapq.merge() 函数可以帮你解决这个问题。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "4\n",
      "5\n",
      "6\n",
      "7\n",
      "10\n",
      "11\n"
     ]
    }
   ],
   "source": [
    "import heapq\n",
    "\n",
    "a = [1, 4, 7, 10]\n",
    "b = [2, 5, 6, 11]\n",
    "\n",
    "for c in heapq.merge(a, b):\n",
    "    print(c)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 16.迭代器代替while无限循环\n",
    "\n",
    "不做笔记了，感觉这部分，就是python里面也不常用的黑魔法。\n",
    "\n",
    "既然是不常用的黑魔法，咱也就不去使用。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  },
  "vscode": {
   "interpreter": {
    "hash": "caf1c2fcf97217de91eafa76b907d50f9ea378f5ffbee7f571142d119bb6a771"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
